//
//  NMTheme.swift
//  NetEaseMusic
//
//  Created by SAGESSE on 2020/2/29.
//  Copyright © 2020 SAGESSE. All rights reserved.
//

import UIKit


func rgb(_ value: UInt64) -> UIColor {
    return UIColor(red: .init(value >> 16 & 0xff) / 255.0, green: .init(value >> 8 & 0xff) / 255.0, blue: .init(value >> 0 & 0xff) / 255.0, alpha: 1)
}
func rgba(_ value: UInt64) -> UIColor {
    return UIColor(red: .init(value >> 16 & 0xff) / 255.0, green: .init(value >> 8 & 0xff) / 255.0, blue: .init(value >> 0 & 0xff) / 255.0, alpha: .init(value >> 24 & 0xff) / 255.0)
}

func sf(_ size: CGFloat, name: String = ".SFUI-Regular") -> UIFont {
    
//    if let font = UIFont(name: name, size: size) {
//        return font
//    }
//    
    return UIFont.systemFont(ofSize: size)
}
func helv(_ size: CGFloat, name: String = "Helvetica") -> UIFont {
    
    if let font = UIFont(name: name, size: size) {
        return font
    }
    
    return UIFont.systemFont(ofSize: size)
}


class NMTheme {
    
    struct Style {
        
        let theme: NMTheme
        let key: String

        
        var font: UIFont {
            return theme.font(forKey: key)
        }
        var color: UIColor {
            return theme.color(forKey: key)
        }
        var image: UIImage? {
            return theme.image(forKey: key)
        }
    }
    
    static var shared: NMTheme = .init()
    
    
    init() {
        
        colors["event.background"] = rgba(0x33ffffff)

        colors["event.link"] =  rgba(0xff85b9e6)

        colors["event.level-1"] =  rgba(0x1affffff)
        colors["event.level-2"] =  rgba(0x21000000)
        //colors["event.level-3"] =  rgba(0x1affffff)

//        #colorLiteral(red: 0.521569, green: 0.72549, blue: 0.901961, alpha: 1.0)

        colors["event.normal-1"] = rgba(0xffffffff)
        colors["event.normal-2"] = rgba(0xccffffff)
        colors["event.normal-3"] = rgba(0x8cffffff)

        colors["event.header.title"] = "event.normal-2"
        colors["event.header.subtitle"] = "event.normal-3"
        fonts["event.header.title"] = sf(15)
        fonts["event.header.subtitle"] = sf(11)

        colors["event.footer.items"] = "event.normal-2"
        fonts["event.footer.items"] = sf(12)

        colors["event.deleted.background"] = "event.level-1"
        colors["event.deleted"] = rgba(0x8cffffff)
        fonts["event.deleted"] = helv(14)
        colors["event.deleted.background.nested"] = "event.level-2"


        colors["event.text"] = "event.normal-1"
        colors["event.text.nested"] = "event.normal-2"
        fonts["event.text"] = helv(16)
        fonts["event.text.nested"] = helv(15)

        colors["event.music.title"] = "event.normal-1"
        colors["event.music.subtitle"] = rgba(0xa5ffffff)
        colors["event.music.background"] = "event.level-1"
        colors["event.music.background.nested"] = "event.level-2"
        fonts["event.music.title"] = sf(15)
        fonts["event.music.subtitle"] = sf(12)

        colors["event.music.title.tag"] = rgba(0xffffe7cd)
        fonts["event.music.title.tag"] = sf(9)
        colors["event.music.subtitle.tag"] = rgba(0xffffe7cd)
        fonts["event.music.subtitle.tag"] = sf(9)

        colors["event.video.title"] = rgba(0x99ffffff)
        colors["event.video.subtitle"] = rgba(0x66ffffff)
        colors["event.video.plays"] = rgba(0xffffffff)
        colors["event.video.duration"] = rgba(0xffffffff)
        colors["event.video.background"] = rgba(0xff000000)
        fonts["event.video.title"] = sf(15)
        fonts["event.video.subtitle"] = sf(12)
        fonts["event.video.plays"] = sf(12, name: "Helvetica Neue")
        fonts["event.video.duration"] = sf(12, name: "Helvetica Neue")

        colors["event.video.title.tag"] = rgba(0xffffe7cd)
        fonts["event.video.title.tag"] = sf(9)
        colors["event.video.subtitle.tag"] = rgba(0xffffe7cd)
        fonts["event.video.subtitle.tag"] = sf(9)

        colors["event.referenced.background"] = "event.level-1"

        colors["event.quote.title"] = rgba(0xffffffff)
        colors["event.quote.subtitle"] = rgba(0xa5ffffff)
        colors["event.quote.source"] = "event.normal-3"
        fonts["event.quote.title"] = helv(16)
        fonts["event.quote.subtitle"] = helv(15)
        fonts["event.quote.source"] = sf(12)
        colors["event.quote.separator"] = rgba(0x0cffffff)

        colors["event.shared.tag"] = "event.music.tag"
        colors["event.shared.title"] = "event.music.title"
        colors["event.shared.subtitle"] = "event.music.subtitle"

        colors["event.shared.title.tag"] = "event.music.title.tag"
        colors["event.shared.subtitle.tag"] = "event.music.subtitle.tag"

        colors["event.shared.background"] = "event.music.background"
        fonts["event.shared.tag"] = "event.music.tag"
        fonts["event.shared.title"] = "event.music.title"
        fonts["event.shared.subtitle"] = "event.music.subtitle"
        
//        colors["event.background"] = UIColor.white
//
//        colors["event.link"] =  rgba(0xff507daf)
//
//        colors["event.level-1"] =  rgba(0xfff2f2f2)
//        colors["event.level-2"] =  rgba(0xfffeffff)
//        //colors["event.level-3"] =  rgba(0x1affffff)
//
//        //        #colorLiteral(red: 0.521569, green: 0.72549, blue: 0.901961, alpha: 1.0)
//
//        colors["event.normal-1"] = rgba(0xff333333)
//        colors["event.normal-2"] = rgba(0xff666666)
//        colors["event.normal-3"] = rgba(0xff999999)
//
//        colors["event.header.title"] = "event.normal-2"
//        colors["event.header.subtitle"] = "event.normal-3"
//        fonts["event.header.title"] = sf(15)
//        fonts["event.header.subtitle"] = sf(11)
//
//        colors["event.footer.items"] = "event.normal-2"
//        fonts["event.footer.items"] = sf(12)
//
//        colors["event.deleted.background"] = "event.level-1"
//        colors["event.deleted"] = "event.level-1"
//        fonts["event.deleted"] = helv(14)
//        colors["event.deleted.background.nested"] = "event.level-2"
//
//
//        colors["event.text"] = "event.normal-1"
//        colors["event.text.nested"] = "event.normal-2"
//        fonts["event.text"] = helv(16)
//        fonts["event.text.nested"] = helv(15)
//
//        colors["event.music.title"] = "event.normal-1"
//        colors["event.music.subtitle"] = "event.normal-3"
//        colors["event.music.background"] = "event.level-1"
//        colors["event.music.background.nested"] = "event.level-2"
//        fonts["event.music.title"] = sf(15)
//        fonts["event.music.subtitle"] = sf(12)
//
//        colors["event.music.title.tag"] = rgba(0xffef3a39)
//        fonts["event.music.title.tag"] = sf(9)
//        colors["event.music.subtitle.tag"] = rgba(0xffef3a39)
//        fonts["event.music.subtitle.tag"] = sf(9)
//
//        colors["event.video.title"] = rgba(0x99ffffff)
//        colors["event.video.subtitle"] = rgba(0x66ffffff)
//        colors["event.video.plays"] = rgba(0xffffffff)
//        colors["event.video.duration"] = rgba(0xffffffff)
//        colors["event.video.background"] = rgba(0xff000000)
//        fonts["event.video.title"] = sf(15)
//        fonts["event.video.subtitle"] = sf(12)
//        fonts["event.video.plays"] = sf(12, name: "Helvetica Neue")
//        fonts["event.video.duration"] = sf(12, name: "Helvetica Neue")
//
//        colors["event.video.title.tag"] = rgba(0xffef3a39)
//        fonts["event.video.title.tag"] = sf(9)
//        colors["event.video.subtitle.tag"] = rgba(0xffef3a39)
//        fonts["event.video.subtitle.tag"] = sf(9)
//
//        colors["event.referenced.background"] = "event.level-1"
//
//        colors["event.quote.title"] = "event.normal-1"
//        colors["event.quote.subtitle"] = "event.normal-3"
//        colors["event.quote.source"] = "event.normal-3"
//        fonts["event.quote.title"] = helv(16)
//        fonts["event.quote.subtitle"] = helv(15)
//        fonts["event.quote.source"] = sf(12)
//        colors["event.quote.separator"] = rgba(0xffd9d9d9)
//
//        colors["event.shared.tag"] = "event.music.tag"
//        colors["event.shared.title"] = "event.music.title"
//        colors["event.shared.subtitle"] = "event.music.subtitle"
//
//        colors["event.shared.title.tag"] = "event.music.title.tag"
//        colors["event.shared.subtitle.tag"] = "event.music.subtitle.tag"
//
//        colors["event.shared.background"] = "event.music.background"
//        fonts["event.shared.tag"] = "event.music.tag"
//        fonts["event.shared.title"] = "event.music.title"
//        fonts["event.shared.subtitle"] = "event.music.subtitle"
    }
    
    func font(forKey key: String) -> UIFont {
        switch fonts[key] {
        case let ref as String:
            return font(forKey: ref)
            
        case let value as UIFont:
            return value
            
        default:
            print("\"\(key)\" font not found")
            return UIFont.systemFont(ofSize: UIFont.systemFontSize)
        }
    }
    
    func color(forKey key: String) -> UIColor {
        switch colors[key] {
        case let ref as String:
            return color(forKey: ref)
            
        case let value as UIColor:
            return value
            
        default:
            return UIColor.red
        }
    }
    
    func image(forKey key: String) -> UIImage? {
        switch images[key] {
        case let ref as String:
            return image(forKey: ref)
            
        case let value as UIImage:
            return value
            
        default:
            return nil
        }
    }
    
    subscript (_ key: String) -> Style {
        return Style(theme: self, key: key)
    }

    fileprivate var images: [String: Any] = [:]
    fileprivate var colors: [String: Any] = [:]
    fileprivate var fonts: [String: Any] = [:]
}


extension NMEvent {
    
    
    var theme: NMTheme {
        guard isReferenced else {
            return NMTheme.shared
        }
        class NMThemeR: NMTheme {
            
            static var shared2: NMThemeR = .init()

            override func font(forKey key: String) -> UIFont {
                switch fonts[key + ".nested"] {
                case let ref as String:
                    return font(forKey: ref)
                    
                case let value as UIFont:
                    return value
                    
                default:
                    return super.font(forKey: key)
                }
            }

            override func color(forKey key: String) -> UIColor {
                switch colors[key + ".nested"] {
                case let ref as String:
                    return color(forKey: ref)
                    
                case let value as UIColor:
                    return value
                    
                default:
                    return super.color(forKey: key)
                }
            }
        }
        
        return NMThemeR.shared2
    }
    
}

// MARK: -

extension NSTextAttachment2 {
    
    convenience init(string: String, style: NMTheme.Style) {
        self.init(string: string, color: style.color, font: style.font)
    }

}

extension NSMutableAttributedString {
    
    convenience init(string: String, style: NMTheme.Style) {
        self.init(string: string, attributes: [ .font: style.font, .foregroundColor: style.color ])
        self.taged(style.theme[style.key + ".tag" ])
    }
    
    
    @discardableResult
    func taged(_ style: NMTheme.Style) -> Self {
        var offset = 0
        
        // Use detector to examine the entire string.
        Self.regex?.enumerateMatches(in: string, range: NSMakeRange(0, length)) { (result, _, _) in
            // Match successful, check the match result。
            guard var range = result?.range, range.location != NSNotFound else {
                return
            }
            
            // Calibration the matches range.
            range.location += offset
            
            // Gets the inserted point attributes.
            let oldAttributes = attributes(at: range.location, effectiveRange: nil)
            let newValue = mutableString.substring(with: NSMakeRange(range.location + 1, range.length - 2))
            
            //
            let attachment = NSTextAttachment2(string: newValue, style: style)
            attachment.padding = .init(top: 0.75, left: 2, bottom: 1, right: 2)
            attachment.margin = .init(top: 1, left: 0, bottom: 0, right: 2)
            replaceCharacters(in: range, with: .init(attachment: attachment))
            offset -= range.length - 1
            range = NSMakeRange(range.location, 1)
            addAttributes(oldAttributes, range: range)
        }
        
        return self
    }

    private static var regex: NSRegularExpression? = try? .init(pattern: "(\\{[^\\{\\}]+\\})")
}


//@IBDesignable class NMThemeGradientButton: UIButton {
////    @IBInspectable var orientation: CGSize = .init(width: 1, height: 1)
////
////    @IBInspectable var startColor: UIColor?
////    @IBInspectable var startColorKey: String?
////
////    @IBInspectable var endColor: UIColor?
////    @IBInspectable var endColorKey: String?
////
////    @IBInspectable var textColor: UIColor?
////    @IBInspectable var textColorKey: String?
////
////    @IBInspectable var iconColor: UIColor?
////    @IBInspectable var iconColorKey: String?
//}



@IBDesignable class NMThemeButton: UIButton {
    
    @IBInspectable var theme: String?
    
    // button_default_1
    
    
    override func layoutSubviews() {
        super.layoutSubviews()
    }
    
}

@IBDesignable class NMThemeLabel: UILabel {
    
    /// Initializes and returns a newly allocated view object with the specified frame rectangle.
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    /// Returns an object initialized from data in a given unarchiver.
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        attributedText = super.attributedText
    }

    override var text: String? {
        get { super.text }
        set {
            rawText = newValue
            rawAttributedText = nil
            redraw()
        }
    }
    override var attributedText: NSAttributedString? {
        get { super.attributedText}
        set {
            rawText = nil
            rawAttributedText = newValue
            redraw()
        }
    }
    
    private func redraw() {
        // The text is set?
        guard let text = rawText ?? rawAttributedText?.string else {
            super.attributedText = nil
            return
        }
        var offset = 0
        var newTextAttachments = [String: NSTextAttachment2]()
        let newAttributedText = rawAttributedText?.mutableCopy() as? NSMutableAttributedString ?? NSMutableAttributedString(string: text)
        let oldTextAttachments = cachedTextAttachments
        
        // Use detector to examine the entire string.
        Self.regex?.enumerateMatches(in: text, range: NSMakeRange(0, text.count)) { (result, _, _) in
            // Match successful, check the match result。
            guard var range = result?.range, range.location != NSNotFound else {
                return
            }
            
            // Calibration the matches range.
            range.location += offset
            
            // Gets the inserted point attributes.
            let oldAttributes = newAttributedText.attributes(at: range.location, effectiveRange: nil)
            let newValue = newAttributedText.mutableString.substring(with: NSMakeRange(range.location + 1, range.length - 2))
            
            //
            let attachment = oldTextAttachments?[newValue] ?? makeTextAttachment(newValue)
            newAttributedText.replaceCharacters(in: range, with: .init(attachment: attachment))
            offset -= range.length - 1
            range = NSMakeRange(range.location, 1)
            newAttributedText.addAttributes(oldAttributes, range: range)
            newTextAttachments[newValue] = attachment
        }

        self.cachedTextAttachments = newTextAttachments
        super.attributedText = newAttributedText
    }
    private func makeTextAttachment(_ value: String) -> NSTextAttachment2 {
        
        if let range = value.range(of: "img:") {
            let image = UIImage(named: String(value[range.upperBound ..< value.endIndex]))
            let attachment = NSTextAttachment2()
            attachment.alignment = .center
            attachment.image = image
            return attachment
        }

        let attachment = NSTextAttachment2(string: value, color: .red, font: sf(9))
        attachment.padding = .init(top: 0.75, left: 2, bottom: 1, right: 2)
        attachment.margin = .init(top: 1, left: 0, bottom: 0, right: 2)
        return attachment
    }
    
    private var rawText: String?
    private var rawAttributedText: NSAttributedString?
    private var cachedTextAttachments: [String: NSTextAttachment2]?

    private static var regex: NSRegularExpression? = try? .init(pattern: "(\\{[^\\{\\}]+\\})")
}




